use thiserror::Error as ErrorTrait;

#[derive(Debug, ErrorTrait)]
pub enum Error {
    #[error("链路错误")]
    InvalidData(#[from] rcgen::RcgenError),
}

pub type Result<T> = std::result::Result<T, Error>;

#[derive(Clone)]
pub struct PrivateKey {
    key_pair_der: Vec<u8>,
    pri_key_der: Vec<u8>,
    pub_key: PublicKey,
}

impl PrivateKey {
    pub fn random() -> Self {
        Self::create(None).unwrap()
    }

    pub fn public_key(&self) -> &PublicKey {
        &self.pub_key
    }

    pub(crate) fn create_signed(&self) -> (Vec<u8>, Vec<u8>) {
        // let mut params = rcgen::CertificateParams::default();
        // params.alg = &rcgen::PKCS_ED25519;
        // let cert = rcgen::Certificate::from_params(params).unwrap();
        //let ca = rcgen::Certificate::f
        //cert.serialize_der_with_signer()

        todo!()
    }

    fn create(key_pair_der: Option<&[u8]>) -> Result<Self> {
        let mut params = rcgen::CertificateParams::default();
        params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Constrained(0));
        params.alg = &rcgen::PKCS_ED25519;
        if let Some(der) = key_pair_der {
            params.key_pair = Some(rcgen::KeyPair::from_der(der)?);
        }
        let cert = rcgen::Certificate::from_params(params)?;

        Ok(Self {
            key_pair_der: cert.get_key_pair().serialize_der(),
            pri_key_der: cert.serialize_private_key_der(),
            pub_key: PublicKey {
                der: cert.get_key_pair().public_key_der(),
            },
        })
    }
}

impl TryFrom<&[u8]> for PrivateKey {
    type Error = Error;

    fn try_from(bytes: &[u8]) -> Result<Self> {
        Self::create(Some(bytes))
    }
}

impl AsRef<[u8]> for PrivateKey {
    fn as_ref(&self) -> &[u8] {
        self.key_pair_der.as_ref()
    }
}

#[derive(Clone)]
pub struct PublicKey {
    der: Vec<u8>,
}

impl TryFrom<&[u8]> for PublicKey {
    type Error = Error;

    fn try_from(bytes: &[u8]) -> Result<Self> {
        Ok(Self {
            der: bytes.to_vec(),
        })
    }
}

impl AsRef<[u8]> for PublicKey {
    fn as_ref(&self) -> &[u8] {
        self.der.as_ref()
    }
}

#[cfg(test)]
mod test {
    use rand::RngCore;
    use ring::signature::KeyPair;

    #[test]
    fn test1() {
        let test_word = b"hello world";

        let mut private_key = [0; 32];
        rand::thread_rng().fill_bytes(&mut private_key);

        let key_pair = efficient_sm2::KeyPair::new(&private_key).unwrap();

        // signing in sm2
        let sig = key_pair.sign(test_word).unwrap();

        // verification sm2 signature
        sig.verify(&key_pair.public_key(), test_word).unwrap();
    }

    #[test]
    fn test2() {
        // Generate a key pair in PKCS#8 (v2) format.
        let rng = ring::rand::SystemRandom::new();
        let pkcs8_bytes = ring::signature::Ed25519KeyPair::generate_pkcs8(&rng).unwrap();

        // Normally the application would store the PKCS#8 file persistently. Later
        // it would read the PKCS#8 file from persistent storage to use it.

        let key_pair = ring::signature::Ed25519KeyPair::from_pkcs8(pkcs8_bytes.as_ref()).unwrap();

        // Sign the message "hello, world".
        const MESSAGE: &[u8] = b"hello, world";
        let sig = key_pair.sign(MESSAGE);

        // Normally an application would extract the bytes of the signature and
        // send them in a protocol message to the peer(s). Here we just get the
        // public key key directly from the key pair.
        let peer_public_key_bytes = key_pair.public_key().as_ref();

        // Verify the signature of the message using the public key. Normally the
        // verifier of the message would parse the inputs to this code out of the
        // protocol message(s) sent by the signer.
        let peer_public_key = ring::signature::UnparsedPublicKey::new(
            &ring::signature::ED25519,
            peer_public_key_bytes,
        );
        peer_public_key.verify(MESSAGE, sig.as_ref()).unwrap();
    }

    #[test]
    fn test3() {
        // let mut seed = [0u8; 32];
        // rand::rngs::OsRng::default().fill_bytes(&mut seed);
        // let key_pair = ring::signature::Ed25519KeyPair::from_seed_unchecked(&seed).unwrap();
        let rng = ring::rand::SystemRandom::new();
        let pkcs8_bytes = ring::signature::Ed25519KeyPair::generate_pkcs8(&rng).unwrap();
        let key_pair = rcgen::KeyPair::from_der(pkcs8_bytes.as_ref()).unwrap();

        let mut cert_params = rcgen::CertificateParams::default();
        cert_params.alg = &rcgen::PKCS_ED25519;
        cert_params.key_pair = Some(key_pair);
        let cert = rcgen::Certificate::from_params(cert_params).unwrap();
        println!("{}", cert.serialize_der().unwrap().len());
        println!("{}", cert.serialize_pem().unwrap().len());
        println!("{}", cert.serialize_pem().unwrap());
    }
}
